import os
import sys
import time
import importlib

from lib import console, log, keyboard, net
from lib import event, world

# helper imports
from lib.console import cwrite

server = None
mainEventQueue = None
keyboardPoller = None
gameWorld = None
worldProcessor = None

def createWorldFromPackage(packageName):
	"""
	Dynamically finds and imports in the World game object from the given package.
	"""
	fullName = "World"
	if packageName != "": fullName = packageName + "." + fullName
	world_module = importlib.import_module(fullName)
	world_class = getattr(world_module, "GameWorld")
	return world_class(packageName)
	
def initializeGlobals(gamePackageName, address, port):
	log.info("initializing globals")
	global server
	global mainEventQueue
	global keyboardPoller
	global gameWorld
	global worldProcessor
	# add the root of the game package to python
	sys.path.append(os.path.join(os.path.dirname(__file__), gamePackageName))
	# initialize console writer (synchronizes writes to the console)
	console.initialize_console()
	# initialize the main event queue
	mainEventQueue = event.EventQueue()
	# start the keyboard polling thread
	keyboardPoller = keyboard.KeyboardPollerThread(mainEventQueue)
	keyboardPoller.start()
	# create the world
	gameWorld = createWorldFromPackage(gamePackageName)
	# create and start the world processor
	worldProcessor = world.WorldProcessingThread(gameWorld)
	worldProcessor.start()
	# create network server
	server = net.NetworkServer(address, port, mainEventQueue)
	server.start()
	
def finalizeGlobals():
	log.info("finalizing globals")
	global server
	global mainEventQueue
	global keyboardPoller
	global worldProcessor
	if server: server.stop()
	if keyboardPoller: keyboardPoller.stop()
	if worldProcessor: worldProcessor.stop()

def enterRunloop():
	log.info("entering run loop")
	done = False
	while not done:
		if not mainEventQueue.noEvents:
			next_event = mainEventQueue.nextEvent()
			if isinstance(next_event, keyboard.KeyboardEvent):
				keyboard_command = next_event.eventData
				if keyboard_command == "quit":
					done = True
				else:
					gameWorld.consoleCommand(keyboard_command)
			elif isinstance(next_event, net.NetworkReceivedDataEvent):
				message = next_event.eventData
				connection = next_event.eventContext
				if message['type'] == "COMMAND":
					# todo: map connection to player
					gameWorld.networkCommand(connection, message['command'])
			elif isinstance(next_event, net.NetworkConnectionEvent):
				connected = next_event.eventData
				connection = next_event.eventContext
				if connected:
					gameWorld.connect(connection)
				else:
					gameWorld.disconnect(connection)
					
		time.sleep(0.01)
	log.info("exiting run loop")

def help():
	print 'server.py <gamepackage> address:port'

def main():
	
	if len(sys.argv) != 3:
		help()
		sys.exit(1)
	
	gamePackageName = sys.argv[1]
	
	try:
		address, port = sys.argv[2].split(':')
		port = int(port)
	except:
		help()
		sys.exit(1)
	
	# initialize globals
	initializeGlobals(gamePackageName, address, port)
	
	# initialize world
	gameWorld.initGame()
	
	# enter run loop
	enterRunloop()
	
	# finalize game
	gameWorld.finalizeGame()
	
	# clean stuff up
	finalizeGlobals()

if __name__ == '__main__':
	main()
